﻿using System;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using MCORP.Framework.Dominio.Entity;
using MCORP.Framework.Dominio.IRepository;
using Microsoft.Practices.ServiceLocation;

namespace MCORP.Framework.Business.Repository
{
    public abstract class BaseRepository<T> : IBaseRepository<T> where T : class
    {
        #region ::. Fields .::

        private readonly ObjectContext _objectContext;

        protected BaseRepository()
        {
            _objectContext = new EasyFinanceEntities();
        }

        #endregion

        #region ::. Properties .::

        public ObjectContext Container
        {
            get { return ServiceLocator.Current.GetInstance<EasyFinanceEntities>(); }
        }

        internal string KeyFieldName
        {
            get
            {
                return ObjectSet.EntitySet.ElementType.KeyMembers[0].Name;
            }
        }

        internal ObjectSet<T> ObjectSet
        {
            get
            {
                var obj = Container.CreateObjectSet<T>();
                return obj;
            }
        }

        #endregion

        #region ::. Methods .::

        public void Delete(T pEntity)
        {
            Container.DeleteObject(pEntity);
        }

        public void Attach(T pEntity)
        {
            Container.AttachTo(pEntity.GetType().Name, pEntity);
        }

        public void Detach(T pEntity)
        {
            Container.Detach(pEntity);
        }

        public void Save(T pEntity)
        {
            var keyValue = (int)pEntity.GetType().InvokeMember(ObjectSet.EntitySet.ElementType.KeyMembers[0].Name, BindingFlags.GetProperty, null, pEntity, null);

            try
            {
                if (keyValue <= 0)
                {
                    _objectContext.AddObject(pEntity.GetType().Name, pEntity);
                    //ObjectSet.AddObject(pEntity);
                }
                else
                {
                    ObjectStateEntry objectStateEntry;
                    _objectContext.ObjectStateManager.TryGetObjectStateEntry(pEntity, out objectStateEntry);

                    if (objectStateEntry == null)
                    {
                        _objectContext.GetObjectByKey(((IEntityWithKey)pEntity).EntityKey);
                        _objectContext.ApplyCurrentValues(((IEntityWithKey)pEntity).EntityKey.EntitySetName, pEntity);
                    }
                }

                _objectContext.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            //var type = typeof(T);
            //var KeyFieldValue = type.InvokeMember(KeyFieldName, BindingFlags.GetProperty, null, pEntity, null);

            //try
            //{
            //    if ((int)KeyFieldValue == 0)
            //    {
            //        Container.AddObject(pEntity.GetType().Name, pEntity);
            //    }
            //    else
            //    {
            //        Container.ApplyCurrentValues(pEntity.GetType().Name, pEntity);
            //    }
            //}
            //catch (Exception ex)
            //{
            //    throw new Exception(ex.Message);
            //}
        }

        public IQueryable<T> Find(Expression<Func<T, bool>> where)
        {
            return Container.CreateObjectSet<T>().Where(where);
        }

        public IQueryable<T> GetAll()
        {
            return Container.CreateObjectSet<T>();
        }

        public void SaveChanges()
        {
            Container.SaveChanges();
        }

        #endregion
    }
}
